<?php
/**
 * Default CRUD controller with fallback view scripts
 * @author Tomáš Fejfar
 *
 */
abstract class Zfb_Controller_Action_Crud extends zfb_Controller_Action_Default 
{
	/**
	 * name of model class
	 * @var string
	 */
	protected $_modelClass;
	/**
	 * Name of insert/update form class
	 * @var string
	 */
	protected $_formClass;
	/**
	 * Name of filter form class
	 * @var string
	 */
	protected $_filterFormClass;
	/**
	 * Page title
	 * @var string
	 */
	protected $_title = 'Untitled';
	/**
	 * Model instance
	 * @var mixed
	 */
	protected $_model;
	/**
	 * Insert/update form instance
	 * @var TF_Form
	 */
	protected $_form;
	/**
	 * Filter form instance
	 * @var TF_Form
	 */
	protected $_filterForm;
	/**
	 * Default view key to look into for view scripts if concrete view scripst 
	 * are missing. 
	 * @var string
	 */
	private $_defaultViewKey = 'crud';
	private $_indexUrl;
	private $_action;
	private $_controller;
	private $_module;
	
	/**
	 * @return void
	 */
	public function init()
	{
		parent::init();
		$this->_model = new $this->_modelClass;
		$this->_form = new $this->_formClass;
		$this->view->title = $this->_title;
		$this->_indexUrl = $this->view->url('index');
	}
	
	public function preDispatch()
	{
		// Po provedení akce je nastaven titlek
		$this->view->headTitle()->prepend($this->_title);
		$r = Zend_Controller_Front::getInstance()->getRequest();
		$this->_module = $r->getModuleName();
		$this->_controller = $r->getControllerName();
		$this->_action = $r->getActionName();
		$this->view->viewKey = $this->_controller;
		
	}
    /**
     * Lists items
     * @return void
     */
    public function indexAction ()
    {
    	if(null !== $this->_filterFormClass){
    		$this->view->form = $this->_filterForm = new $this->_filterFormClass;
    	}
    	$filter = null;
    	if(null !== $this->_filterFormClass){
    		if($this->_getParam('filter') && $this->_filterForm->isValid($this->_getAllParams())){
    			$filter = $this->_filterForm->getValues();
    		}
    		$this->_filterForm->populate($this->_getAllParams());
    		
    	}
        /* @var Tul_Paginator */
        $paginator = Zfb_Paginator::factory($this->_model->getAllSelect($filter), $this->_getParam('page',1));
        $this->view->paginator = $paginator;
        $this->_renderView('index.phtml');
    }
    
    protected function _gotoIndex()
    {
    	$this->_gotoUrl($this->_indexUrl);
    }
    
    /**
     * Returns ID if present, else it redirects to index with error message.
     * @return int
     */
    public function getId()
    {
    	$id = $this->_getParam('id', false);
    	if(false === $id){
    		$this->_addFlashMessage('error', 'invalid_id');
    		$this->_gotoIndex();
    	}
    	return $id;
    }
    
    /**
     * Inserts new entry
     * @return void
     */
    public function insertAction ()
    {
    	$this->view->headTitle()->prepend($this->translate('insert'));
    	if ($this->_request->isPost()) {
            if ($this->_form->isValid($_POST)) {
                $data = $this->_form->getValues();
                $this->_beforeInsert($data);
                $result = $this->_model->insert($data);
	            $this->_afterInsert($data, $result);
	            if(null !== $result){ 
             	   	$this->_addFlashMessage('success','insert_successful');
	            } else {
	            	$this->_addFlashMessage('error','insert_error', htmlspecialchars($e->getMessage()));
	            }
                	
                $this->_gotoIndex();
            } else {
                $this->_form->populate($_POST);
            }
        }
        $this->view->form = $this->_form;
        $this->_renderView('insert.phtml');
    } 

    /**
     * Deletes an entry
     * @return void
     */
    public function deleteAction ()
    {
    	$id = $this->getId();    	
    	$this->_beforeDelete($id);
    	$result = $this->_model->delete($this->_model->quoteInto('id = ?',$id));
    	$this->_afterDelete($id, $result);
    	if($result == 1){
    		$this->_addFlashMessage('success','delete_successful');
    	} else {
    		$this->_addFlashMessage('error','delete_error',$result);	
    	}
		$this->_gotoIndex();
    } 
    
    /**
     * Updates an entry
     * @return void
     */
    public function updateAction ()
    {
    	$this->view->headTitle()->prepend($this->translate('update'));
        $id = $this->getId();
        $item = $this->_model->getById($id);
        if ($this->_request->isPost()) {
            if ($this->_form->isValid($_POST)) {
                $data = $this->_form->getValues();
                try {
                	$this->_beforeUpdate($data, $item);
                	$result = $this->_model->update($data, $this->_model->quoteInto('id = ?',$id));
                	$this->_afterUpdate($data, $result);
                	$this->_addFlashMessage('success','update_successful');
                } catch (Exception $e){
                	$this->_addFlashMessage('error','update_error', htmlspecialchars($e->getMessage()));
                }
                $this->_gotoIndex();
            } else {
                $this->_form->populate($_POST);
            }
        } else {
            $this->_form->populate((array)$item);
        }
        $this->view->form = $this->_form;
        $this->_renderView('update.phtml');
    }
    
    /**
     * If view exists renders it else it renders fallback view
     * @param $name string view filename (inc. suffix)
     * @return void
     */
    private function _renderView($name)
    {
    	$completeName = $this->_controller . '/' . $name;
    	/* @var Zend_View_Abstract */
    	foreach ($this->view->getScriptPaths() as $dir) {
            if (is_readable($dir . $completeName)) {
            	return $this->renderScript($completeName);
            }
        }
        return $this->renderScript($this->_defaultViewKey . '/' . $name);
    }

    /**
     * Called before inserting data
     * @param $data array data
     * @return void
     */
    protected function _beforeInsert(&$data){}
    /**
     * Called after inserting data
     * @param $data array data
     * @param $result int|null inserted item PK
     * @return void
     */
    protected function _afterInsert(&$data, $result){}
    /**
     * Called before updating
     * @param $data array data
     * @param $item array|object original data
     * @return void
     */
    protected function _beforeUpdate(&$data,$item){}
    /**
     * Called after updating
     * @param $data array data
     * @param $result integer number of affected rows
     * @return void
     */
    protected function _afterUpdate(&$data,$result){}
    /**
     * Called before deleting
     * @param $id int id of entry
     * @return void
     */
    protected function _beforeDelete($id){}
    /**
     * Called after deleting
     * @param $id int id of entry
     * @param $result integer number of affected rows
     * @return void
     */
    protected function _afterDelete($id, $result){}    
}